﻿using System;
using System.Runtime.Serialization;

namespace Loki.Utils
{
    /// <summary>
    /// Provides a weak reference to an object of the given type to be used in a WeakDictionary along with the given comparer.
    /// </summary>
    /// <typeparam name="T">The weak reference type.</typeparam>
    [Serializable]
    public class WeakKeyReference<T> : WeakReference<T> where T : class
    {
        private readonly int HASH_CODE;

        public int KeyHashCode
        {
            get
            {
                return HASH_CODE;
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WeakKeyReference&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="P_Key">The key.</param>
        /// <param name="P_Comparer">The comparer.</param>
        public WeakKeyReference(T P_Key, WeakKeyComparer<T> P_Comparer)
            : base(P_Key)
        {
            // retain the object's hash code immediately so that even
            // if the target is GC'ed we will be able to find and
            // remove the dead weak reference.
            HASH_CODE = P_Comparer.GetHashCode(P_Key);
        }

        /// <summary>
        /// Remplit un objet <see cref="T:System.Runtime.Serialization.SerializationInfo"/> de toutes les données nécessaires à la sérialisation de l'objet <see cref="T:System.WeakReference"/> en cours.
        /// </summary>
        /// <param name="P_Info">Objet contenant toutes les données nécessaires pour sérialiser ou désérialiser l'objet <see cref="T:System.WeakReference"/> actuel.</param>
        /// <param name="P_Context">Réservé: Emplacement où les données sérialisées sont stockées et récupérées.</param>
        /// <exception cref="T:System.ArgumentNullException">Le paramètre <paramref name="P_Info"/> est null. </exception>
        public override void GetObjectData(SerializationInfo P_Info, StreamingContext P_Context)
        {
            P_Info.AddValue(HASH_CODE_NAME, HASH_CODE);
            base.GetObjectData(P_Info, P_Context);
        }

        protected WeakKeyReference(SerializationInfo P_Info, StreamingContext P_Context)
            : base(P_Info, P_Context)
        {
            HASH_CODE = P_Info.GetInt32(HASH_CODE_NAME);
        }

        private const string HASH_CODE_NAME = "KeyHashCode";
    }
}
